"""
Grave! Important! Важно!

Proletoj el ĉiuj landoj, unuiĝu!
Workers of the world, unite!
Пролетарии всех стран, соединяйтесь!

https://tkom.pro
"""

from django.db import models
from django.db.models import Max, Q
from django.contrib.auth.models import Permission
from django.utils.translation import gettext_lazy as _
from siriuso.models.postgres import CallableEncoder
from siriuso.utils import default_lingvo, get_enhavo
from main.models import SiriusoBazaAbstrakta3, SiriusoBazaAbstraktaUzanto, Uzanto, SiriusoBazaAbstrakta2
from siriuso.utils import perms
import sys
import random
import string

from embed_video.fields import EmbedVideoField

# Генерация случайного названия и переименование загружаемых файлов
def memorkartoj_bildo(instance, filename):
    letters = string.ascii_letters + string.digits
    rnd_string = ''.join(random.choice(letters) for i in range(10))
    # указание папки для хранения файлов и собирание конечного названия с сохранением изначального расширения
    return 'memorkartoj/bildo/{0}.{1}'.format(rnd_string, filename.split('.')[-1])

# Модуль карточек
class MemorkartojModulo(SiriusoBazaAbstraktaUzanto):

    # ID записи
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # название модуля, от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание модуля, от туда будет браться описание с нужным языковым тегом
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'memorkartoj_modulo'
        # читабельное название модели, в единственном числе
        verbose_name = _('Modulo')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Moduloj')
        # права
        permissions = (
            ('povas_vidi_modulo', _('Povas vidi modulo')),
            ('povas_krei_modulo', _('Povas krei modulo')),
            ('povas_forigi_modulo', _('Povas forigu modulo')),
            ('povas_shanghi_modulo', _('Povas ŝanĝi modulo')),
        )

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):

        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(MemorkartojModulo, self).save(force_insert=force_insert, force_update=force_update,
                                           using=using, update_fields=update_fields)

    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения мессенджера
            all_perms = set(perms.user_registrita_perms(apps=('memorkartoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'memorkartoj.povas_vidi_modulo', 'memorkartoj.povas_krei_modulo',
                'memorkartoj.povas_forigi_modulo', 'memorkartoj.povas_shanghi_modulo',
                'memorkartoj.povas_krei_karto'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='memorkartoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('memorkartoj.povas_vidi_modulo')
                    or user_obj.has_perm('memorkartoj.povas_vidi_modulo')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('memorkartoj.povas_vidi_modulo'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond

# Генерация случайного названия и переименование загружаемых файлов
def memorkartoj_sono(instance, filename):
    letters = string.ascii_letters + string.digits
    rnd_string = ''.join(random.choice(letters) for i in range(10))
    # указание папки для хранения файлов и собирание конечного названия с сохранением изначального расширения
    return 'memorkartoj/sono/{0}.{1}'.format(rnd_string, filename.split('.')[-1])

# Карточка
class MemorkartojKarto(SiriusoBazaAbstrakta3):

    # ID записи / очередность в модуле
    id = models.IntegerField(_('ID'), default=0)

    # в каком модуле
    posedanto = models.ForeignKey(MemorkartojModulo, verbose_name=_('Modula'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # название карточки (термин), от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание карточки (определение), от туда будет браться описание с нужным языковым тегом
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # присоединенное изображение
    bildo = models.ImageField(_('Bildo'), upload_to=memorkartoj_bildo, blank=True)

    # присоединенный звук
    sono = models.FileField(_('Sono'), upload_to=memorkartoj_sono, blank=True)

    # видео
    video = EmbedVideoField(verbose_name=_('Video'), blank=True, default='')

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'memorkartoj_karto'
        # читабельное название модели, в единственном числе
        verbose_name = _('Karto')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Kartoj')
        # уникальность
        unique_together = ("id","posedanto")
        # права
        permissions = (
            ('povas_vidi_karto', _('Povas vidi karto')),
            ('povas_krei_karto', _('Povas krei karto')),
            ('povas_forigi_karto', _('Povas forigu karto')),
            ('povas_shanghi_karto', _('Povas ŝanĝi karto')),
        )

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):

        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.filter(posedanto=self.posedanto).aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(MemorkartojKarto, self).save(force_insert=force_insert, force_update=force_update,
                                           using=using, update_fields=update_fields)

    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения мессенджера
            all_perms = set(perms.user_registrita_perms(apps=('memorkartoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'memorkartoj.povas_vidi_karto', 'memorkartoj.povas_krei_karto',
                'memorkartoj.povas_forigi_karto', 'memorkartoj.povas_shanghi_karto'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='memorkartoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('memorkartoj.povas_vidi_karto')
                    or user_obj.has_perm('memorkartoj.povas_vidi_karto')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('memorkartoj.povas_vidi_karto'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond

# Тип теста/игры
class MemorkartojTesto(SiriusoBazaAbstrakta3):

    # ID записи / очередность в модуле
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # название карточки (термин), от туда будет браться название с нужным языковым тегом
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание карточки (определение), от туда будет браться описание с нужным языковым тегом
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'memorkartoj_testo'
        # читабельное название модели, в единственном числе
        verbose_name = _('Testo')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Testoj')
        # права
        permissions = (
            ('povas_vidi_testo', _('Povas vidi testo')),
            ('povas_krei_testo', _('Povas krei testo')),
            ('povas_forigi_testo', _('Povas forigu testo')),
            ('povas_shanghi_testo', _('Povas ŝanĝi testo')),
        )

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):

        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id = next_id + 1
            super(model, self).__setattr__('id', next_id)

        super(MemorkartojTesto, self).save(force_insert=force_insert, force_update=force_update,
                                           using=using, update_fields=update_fields)

    @staticmethod
    def _get_perm_cond(user_obj):
        return Q()

# Статистика тестов
class MemorkartojStatistiko(SiriusoBazaAbstrakta2):

    # тип теста
    testo = models.ForeignKey(MemorkartojTesto, verbose_name=_('Testo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # карточка
    karto = models.ForeignKey(MemorkartojKarto, verbose_name=_('Karto'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # автор (пользователь, который создал сущность или для которого создана сущность)
    autoro = models.ForeignKey(Uzanto, verbose_name=_('Aŭtoro'), blank=False, default=None, on_delete=models.CASCADE)

    # количество проходов данного теста
    nombro = models.IntegerField(_('Nombro'), default=0)

    # количество успешных проходов
    sukcesa = models.IntegerField(_('Sukcesa'), default=0)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'memorkartoj_statistiko'
        # читабельное название модели, в единственном числе
        verbose_name = _('Statistiko')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Statistikoj')
        # уникальность
        unique_together = ("testo","karto","autoro")
        # права
        permissions = (
            ('povas_vidi_statistiko', _('Povas vidi statistiko')),
            ('povas_krei_statistiko', _('Povas krei statistiko')),
            ('povas_forigi_statistiko', _('Povas forigu statistiko')),
            ('povas_shanghi_statistiko', _('Povas ŝanĝi statistiko')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # return str(self.uuid)
        return '{}) {} - {}){} - {} {} {}'.format(self.testo.id,
            get_enhavo(self.testo.nomo, empty_values=True)[0],
            self.karto.id,
            get_enhavo(self.karto.nomo, empty_values=True)[0],
            get_enhavo(self.autoro.unua_nomo, empty_values=True)[0],
            get_enhavo(self.autoro.dua_nomo, empty_values=True)[0],
            get_enhavo(self.autoro.familinomo, empty_values=True)[0])

    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения мессенджера
            all_perms = set(perms.user_registrita_perms(apps=('memorkartoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'memorkartoj.povas_vidi_statistiko', 'memorkartoj.povas_krei_statistiko',
                'memorkartoj.povas_forigi_statistiko', 'memorkartoj.povas_shanghi_statistiko'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='memorkartoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('memorkartoj.povas_vidi_statistiko')
                    or user_obj.has_perm('memorkartoj.povas_vidi_statistiko')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('memorkartoj.povas_vidi_statistiko'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond

# подписка на чужие модули
class MemorkartojAbono(SiriusoBazaAbstrakta3):

    # модуль
    modulo = models.ForeignKey(MemorkartojModulo, verbose_name=_('Testo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # пользователь, для которого создана сущность
    posedanto = models.ForeignKey(Uzanto, verbose_name=_('Posedanto'), blank=False, default=None, on_delete=models.CASCADE)

    # оповещать об изминении в модуле
    # sciigo = models.BooleanField(_('Sciigo'), blank=False, default=True)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'memorkartoj_abono'
        # читабельное название модели, в единственном числе
        verbose_name = _('Abono')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Abonoj')
        # уникальность
        unique_together = ("modulo","posedanto")
        # права
        permissions = (
            ('povas_vidi_abono', _('Povas vidi abono')),
            ('povas_krei_abono', _('Povas krei abono')),
            ('povas_forigi_abono', _('Povas forigu abono')),
            ('povas_shanghi_abono', _('Povas ŝanĝi abono')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # return str(self.uuid)
        return '{}) {} - {} {} {}'.format(self.modulo.id,
            get_enhavo(self.modulo.nomo, empty_values=True)[0],
            get_enhavo(self.posedanto.unua_nomo, empty_values=True)[0],
            get_enhavo(self.posedanto.dua_nomo, empty_values=True)[0],
            get_enhavo(self.posedanto.familinomo, empty_values=True)[0])

    def _get_user_permissions(self, user_obj):
        # Объявляем пустой список прав
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            # Права зарегистриованных для приложения мессенджера
            all_perms = set(perms.user_registrita_perms(apps=('memorkartoj',)))

            # Преобразуем список прав к имени права без приложения, отфильтровывая только нужные для текущей модели
            # и одно право на создание для дочерней модели
            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'memorkartoj.povas_vidi_abono', 'memorkartoj.povas_krei_abono',
                'memorkartoj.povas_forigi_abono', 'memorkartoj.povas_shanghi_abono'
            ))

            # Делаем выборку прав из модели прав Django
            user_perms = Permission.objects.filter(content_type__app_label='memorkartoj', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('memorkartoj.povas_vidi_abono')
                    or user_obj.has_perm('memorkartoj.povas_vidi_abono')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('memorkartoj.povas_vidi_abono'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond

